from httplib import HTTPSConnection
import json
import logging
import os
from django.conf import settings
from django.core.files.temp import NamedTemporaryFile

logger = logging.getLogger(__name__)

NUM_USERS = 10

def print_500_to_file(res, status_code):
    if status_code == 500:
        f = NamedTemporaryFile(delete=False)
        logger.error("Output in file://" + f.name)
        f.write(res)
        f.close()
    else:
        logger.info(res)
    return res

def print_output_to_file_from_client_response(response):
    res = response.content
    status_code = response.status_code
    return print_500_to_file(res, status_code)

def print_output_to_file_from_connection_response(response):
    res = response.read()
    status_code = response.status
    return print_500_to_file(res, status_code)

def perform_connection(connection):
    response = connection.getresponse()
    logger.info(str(response.status) + ',' + str(response.reason))
    output = print_output_to_file_from_connection_response(response)
    return response, output

class TestFacebookUserManager:
    def clear_manager(self):
        self.TEST_FACEBOOK_USERS = []
        self.TEST_FACEBOOK_USERS_FILE = os.path.dirname(__file__) + '/test_facebook_users.json'
        self.read_test_facebook_users()
        if not settings.MOCK_FACEBOOK:
            if settings.FACEBOOK_APP_SECRET == '':
                raise ValueError('Please configure FACEBOOK_APP_SECRET as environment variable')
            self.get_app_access_token()
            self.update_tokens()

    def __init__(self):
        self.clear_manager()

    def get_app_access_token(self):
        self.connection = HTTPSConnection("graph.facebook.com")
        self.connection.request('GET','/oauth/access_token?client_id={facebook_app_id}&client_secret={facebook_app_secret}&grant_type=client_credentials'.
        format(
            facebook_app_id = settings.FACEBOOK_APP_ID,
            facebook_app_secret = settings.FACEBOOK_APP_SECRET))
        response, output = perform_connection(self.connection)
        if response.status != 200:
            raise ValueError("Response is wrong : " + str(response.status) + ": " + output)
        self.app_access_token = output.split('=')[1]
        return self.app_access_token

    def read_test_facebook_users(self):
        try:
            self.TEST_FACEBOOK_USERS = json.load(open(self.TEST_FACEBOOK_USERS_FILE,'r'))
        except IOError as err:
            if err.errno == 2:
                print ('Creating users')
                self.get_app_access_token()
                self.create_users(3)
            else:
                raise err

    def __getitem__(self, item):
        return self.TEST_FACEBOOK_USERS[item]

    def get_users(self):
        self.connection.request('GET', "/{facebook_app_id}/accounts/test-users?installed=true&locale=en_US&"\
                                       "permissions={token_permissions}&access_token={app_access_token}"\
        .format(facebook_app_id = settings.FACEBOOK_APP_ID,
                app_access_token  = self.app_access_token,
                token_permissions = settings.FACEBOOK_PERMISSIONS))
        response, output = perform_connection(self.connection)
        parsed_users = json.loads(output)
        return parsed_users

    def delete_users(self, parsed_users):
        for user in parsed_users['data']:
            self.connection.request('GET', "/{user_id}?method=delete&access_token={access_token}".
            format(user_id = user['id'],access_token  = user['access_token']))
            perform_connection(self.connection)

    def save_users(self):
        file = open(self.TEST_FACEBOOK_USERS_FILE, 'w')
        try:
            json.dump(self.TEST_FACEBOOK_USERS, file, indent=2)
        finally:
            file.close()
        print "Test users created and stored in " + str(file)

    def create_users(self, number_of_users):
        print "Creating " + str(number_of_users) + " users"
        users = []
        for i in range(0,number_of_users):
            print "Creating user " + str(i)
            get_command =  "/{app_id}/accounts/test-users?installed=true&locale=en_US&"\
                           "permissions={token_permissions}&method=post&access_token={app_access_token}".\
            format(
                app_id = settings.FACEBOOK_APP_ID,
                app_access_token  = self.app_access_token,
                token_permissions = settings.FACEBOOK_PERMISSIONS)
            logger.info(get_command)
            self.connection.request('GET',get_command)
            response, output = perform_connection(self.connection)
            if response.status != 200:
                print(response .status + ":" + str(output))
                raise ValueError(response)
            user = json.loads(output)
            self.connection.request('GET','/me&access_token={user_access_token}'.format(user_access_token = user['access_token']))
            response, output = perform_connection(self.connection)
            extra_user_data = json.loads(output)
            user['name'] = extra_user_data['name']
            users.append(user)
        self.TEST_FACEBOOK_USERS = users
        for i in range(0, number_of_users):
            print "Emptying " + str(i) + " friend"
            self.TEST_FACEBOOK_USERS[i]['friends'] = []
        for i in range(0, number_of_users/2):
            print "Making friends for " + self[i]['name']
            for j in range(number_of_users - i, number_of_users):
                if i != j:
                    self.make_friends(i, j)
                    self.TEST_FACEBOOK_USERS[i]['friends'].append(j)
                    self.TEST_FACEBOOK_USERS[j]['friends'].append(i)
        self.save_users()

    def update_tokens(self):
        self.get_app_access_token()
        parsed_users = self.get_users()
        user_map = {}
        for user in parsed_users['data']:
            user_map[user['id']] = user
        for user in self.TEST_FACEBOOK_USERS:
            updated_user =  user_map[user['id']]
            user['access_token'] = updated_user['access_token']

    def get_social_data(self, test_user_number):
        social_token = self.TEST_FACEBOOK_USERS[test_user_number]['access_token']
        social_id = self.TEST_FACEBOOK_USERS[test_user_number]['id']
        social_real_name = self.TEST_FACEBOOK_USERS[test_user_number]['name']
        username = self.TEST_FACEBOOK_USERS[test_user_number]['email']
        return social_real_name, social_token, social_id, username

    def make_friends(self, user_no_1, user_no_2):
        print u"Making friends " + unicode(user_no_1) + u"<->" + unicode(user_no_2)
        user1 = self[user_no_1]
        user2 = self[user_no_2]
        self.connection.request('GET','/{user1_id}/friends/{user2_id}?method=post&access_token={user1_access_token}'
        .format(user1_id = user1['id'],user2_id=user2['id'],user1_access_token = user1['access_token']))
        response, output = perform_connection(self.connection)
        if response.status != 200:
            raise RuntimeError("Error when processing the friend request: status code = " + str(response.status_code) + ", output = " + output)
        self.connection.request('GET','/{user2_id}/friends/{user1_id}?method=post&access_token={user2_access_token}'
        .format(user1_id = user1['id'],user2_id=user2['id'],user2_access_token = user2['access_token']))
        response, output = perform_connection(self.connection)
        if response.status != 200:
            raise RuntimeError("Error when processing the friend request: status code = " + str(response.status_code) + ", output = " + output)

    def append_user(self, user):
        self.TEST_FACEBOOK_USERS.append(user)

    def find_user_by_mail(self, email):
        index = 0
        for user in self.TEST_FACEBOOK_USERS:
            if user['email'] == email:
                return index, user
            index += 1
        return -1, None

    def find_user_by_identifier(self, social_identifier):
        index = 0
        for user in self.TEST_FACEBOOK_USERS:
            if user['id'] == social_identifier:
                return index, user
            index += 1
        return -1, None

MANAGER = TestFacebookUserManager()

def get_shared_facebook_manager():
    return MANAGER

def clear_shared_facebook_manager():
    MANAGER.clear_manager()

if __name__ == '__main__':
    creator = TestFacebookUserManager()
    creator.create_users(NUM_USERS)